/*
 This file 'NumberField' is part of Firebird Integrated Solution 1.0

 Copyright (c) 2015 Lincong

 Contact:  
 Email: lincong1987@gmail.com

 QQ: 159257119

 See Usage at http://www.jplatformx.com/firebird

 Create date: 2015-07-21 00:40
 */

define(function (require, exports, module) {

	require("Firebird.ui.TextField");

	/**
	 *    Desc:        重写toFixed方法，解决IE下浮点数精度问题
	 *    Updater:    Lincong
	 */
	Number.prototype.toFixed = function (fractionDigits) {
		var f = parseInt(fractionDigits) || 0;
		if (f < -20 || f > 100) {
			throw new RangeError("Precision of " + f + " fractional digits is out of range");
		}
		var x = Number(this);
		if (isNaN(x)) {
			return "NaN";
		}

		if (Number(this) == 0) {
			var x = "0.";
			for (var i = 1; i <= f; i++) {
				x = x + "0";
			}
			//fixed 0. bug
			if (x == "0.")x = 0;
			return x;
		}

		var s = "";
		if (x <= 0) {
			s = "-";
			x = -x;
		}
		if (x >= Math.pow(10, 21)) {
			return s + x.toString();
		}
		var m;
// 10. Let n be an integer for which the exact mathematical value of
// n ÷ 10^f - x is as close to zero as possible.
// If there are two such n, pick the larger n.
		n = Math.round(x * Math.pow(10, f));

		if (n == 0) {
			m = "0";
		}
		else {
			// let m be the string consisting of the digits of the decimal representation of n (in order, with no leading zeroes).
			m = n.toString();
		}
		if (f == 0) {
			return s + m;
		}
		var k = m.length;
		if (k <= f) {
			var z = Math.pow(10, f + 1 - k).toString().substring(1);
			m = z + m;
			k = f + 1;
		}
		if (f > 0) {
			var a = m.substring(0, k - f);
			var b = m.substring(k - f);
			m = a + "." + b;
		}
		return s + m;
	};

	/**
	 * Firebird.ui.NumberField
	 * @class Firebird.ui.NumberField
	 */
	Firebird.define("Firebird.ui.NumberField", {
		extend: "Firebird.ui.TextField",

		statics: {
			_uuid: 1,
			uuid: function () {
				return this._uuid++;
			},
			/**
			 * 属性适配器
			 * @param $component
			 * @returns {{}}
			 */
			attrs: function ($component) {
				return $.extend(true, {}, Firebird.ui.TextField.attrs($component), {
					format: $component.attr("fb-format") || "#,##0.00",
					precision: $component.attr("fb-precision") || "2"
				});
			}
		},

		config: {
			renderTo: null,
			instanceId: null,
			width: 222,
			placeholder: null,
			//value: "",

			format: "#,##0.00",
			precision: 2,

			limit: null,
			on: null,
			keyup: null,
			keypress: null,
			keydown: null,
			disabled: false,
			focus: false,
			readonly: false,
			hidden: false
		},

		instance: null,
		wrapper: null,
		wrapCls: "fb-ui-textfield",
		_init: function (config) {
			var me = this;

			me.instance = $(me.getRenderTo()).addClass(this.wrapCls + "-input").data({
				instance: me,
				xtype: "textfield"
			});

			this.render();

			this.setReadonly(this.getReadonly());
			this.setDisabled(this.getDisabled());
			this.setWidth(this.getWidth());
			this.setFocus(this.getFocus());
			this.setHidden(this.getHidden());

			me.setValue(me.instance.attr("fb-value") || me.instance.val() || "");
			this.bindPlaceholder();
		},

		render: function () {
			var me = this;
			me.instance.wrap($("<span class='" + this.wrapCls + "'></span>"));
			var wrapper = this.wrapper = me.instance.parent();

			me.wrapper.data("instance", me);

			var $placeholder = me.$placeholder = $("<span class='" + this.wrapCls + "-placeholder'></span>");
			me.instance.before($placeholder);

			me.instance.on("focus", function () {
				wrapper.addClass(me.wrapCls + "-focus");
				var val = parseFloat(me.realValue, 10).toFixed(parseInt(me.getPrecision(), 10));
				me.instance.val(val == 0 ? "" : val);
				setTimeout(function () {
					me.bindPlaceholder();
					me.instance.trigger("focusout");
				}, 0);
				me.instance.trigger("focusin");
			}).on("change", function () {
				wrapper.addClass(me.wrapCls + "-focus");
				setTimeout(function () {
					me.bindPlaceholder();
				}, 0);
			}).on("blur", function (e) {
				me._setValue(me.instance.val());
				wrapper.removeClass(me.wrapCls + "-focus");
				me.bindPlaceholder();
				me.instance.trigger("focusout");
			}).on("keydown keyup keypress", function () {
				me.bindPlaceholder();
			});

			//this.wrapper.on("mouseover", function () {
			//	me.wrapper.addClass(me.wrapCls + "-hover");
			//	if (me.wrapper.hasClass(me.wrapCls + "-invalid")) {
			//		me.instance.trigger("showErrorMessage");
			//		me.wrapper.removeClass(me.wrapCls + "-invalid");
			//	}
			//});
			//
			//this.wrapper.on("mouseout", function () {
			//	me.wrapper.removeClass(me.wrapCls + "-hover");
			//	if (me.wrapper.hasClass(me.wrapCls + "-invalid")) {
			//		me.instance.trigger("hideErrorMessage");
			//		me.wrapper.removeClass(me.wrapCls + "-invalid");
			//	}
			//});

			this.wrapper.on("mouseover", function () {
				me.wrapper.addClass(me.wrapCls + "-hover");
				if (me.wrapper.hasClass(me.wrapCls + "-invalid")) {
					me.instance.trigger("showErrorMessage");
				}
			});

			this.wrapper.on("mouseout", function () {
				me.wrapper.removeClass(me.wrapCls + "-hover");
				if (me.wrapper.hasClass(me.wrapCls + "-invalid")) {
					me.instance.trigger("hideErrorMessage");
				}
			});


			this.$placeholder.on("click", function () {
				me.setFocus(true);
			});

		},

		realValue: 0,

		getValue: function () {
			return parseFloat(this.realValue, 10).toFixed(parseInt(this.getPrecision(), 10));
		},

		_setValue: function (val) {
			if (typeof val === "undefined" || val === "") {
				val = 0;
			}

			try {
				if (isNaN(val)) {
					val = 0;
				}
			} catch (e) {
			}

			this.realValue = val;
			this.instance.val(this._format(this.getFormat(), val));
			this.bindPlaceholder();
		},

		setValue: function (val) {
			this._setValue(val);
		},


		_format: function (mask, value) {

			if (!mask || isNaN(+value)) {
				return value; // return as it is.
			}
			var isNegative,
				result,
				decimal,
				group,
				posLeadZero,
				posTrailZero,
				posSeparator, part, szSep, integer,
			// find prefix/suffix
				len = mask.length,
				start = mask.search(/[0-9\-\+#]/),
				prefix = start > 0 ? mask.substring(0, start) : '',
			// reverse string: not an ideal method if there are surrogate pairs
				str = mask.split('').reverse().join(''),
				end = str.search(/[0-9\-\+#]/),
				offset = len - end,
				indx = offset + ((mask.substring(offset, offset + 1) === '.') ? 1 : 0),
				suffix = end > 0 ? mask.substring(indx, len) : '';
			// mask with prefix & suffix removed
			mask = mask.substring(start, indx);
			// convert any string to number according to formation sign.
			value = mask.charAt(0) === '-' ? -value : +value;
			isNegative = value < 0 ? value = -value : 0; // process only abs(), and turn on flag.
			// search for separator for grp & decimal, anything not digit, not +/- sign, not #.
			result = mask.match(/[^\d\-\+#]/g);
			decimal = (result && result[result.length - 1]) || '.'; // treat the right most symbol as decimal
			group = (result && result[1] && result[0]) || ','; // treat the left most symbol as group separator
			// split the decimal for the format string if any.
			mask = mask.split(decimal);
			// Fix the decimal first, toFixed will auto fill trailing zero.
			value = value.toFixed(mask[1] && mask[1].length);
			value = +(value) + ''; // convert number to string to trim off *all* trailing decimal zero(es)
			// fill back any trailing zero according to format
			posTrailZero = mask[1] && mask[1].lastIndexOf('0'); // look for last zero in format
			part = value.split('.');
			// integer will get !part[1]
			if (!part[1] || (part[1] && part[1].length <= posTrailZero)) {
				value = (+value).toFixed(posTrailZero + 1);
			}
			szSep = mask[0].split(group); // look for separator
			mask[0] = szSep.join(''); // join back without separator for counting the pos of any leading 0.
			posLeadZero = mask[0] && mask[0].indexOf('0');
			if (posLeadZero > -1) {
				while (part[0].length < (mask[0].length - posLeadZero)) {
					part[0] = '0' + part[0];
				}
			} else if (+part[0] === 0) {
				part[0] = '';
			}
			value = value.toString().split('.');
			value[0] = part[0];
			// process the first group separator from decimal (.) only, the rest ignore.
			// get the length of the last slice of split result.
			posSeparator = (szSep[1] && szSep[szSep.length - 1].length);
			if (posSeparator) {
				integer = value[0];
				str = '';
				offset = integer.length % posSeparator;
				len = integer.length;
				for (indx = 0; indx < len; indx++) {
					str += integer.charAt(indx); // ie6 only support charAt for sz.
					// -posSeparator so that won't trail separator on full length
					/*jshint -W018 */
					if (!((indx - offset + 1) % posSeparator) && indx < len - posSeparator) {
						str += group;
					}
				}
				value[0] = str;
			}
			value[1] = (mask[1] && value[1]) ? decimal + value[1] : '';
			// remove negative sign if result is zero
			result = value.join('');
			if (result === '0' || result === '') {
				// remove negative sign if result is zero
				isNegative = false;
			}
			// put back any negation, combine integer and fraction, and add back prefix & suffix
			return prefix + ((isNegative ? '-' : '') + result) + suffix;
		}

	});

	module.exports = Firebird.ui.NumberField;

});